/**
 * 
 */
package cn.biplam.back.sql.procedure;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Map;

import cn.biplam.back.sql.type.Type;
import cn.biplam.common.wrapper.ErrorMessage;
import cn.biplam.common.wrapper.KvMap;

/**
 * 存储过程模型类
 * @author 	WangSong 2009-9-14 下午05:12:45
 * @version 1.0
 */
public class Procedure implements Serializable {

	private static final long serialVersionUID = -7485486474296499050L;

	/**名称*/
	String sName;

	/**起始语句*/ //名称关键字%PNAME%
	String sBegin;
	/**结束语句*/	//名称关键字%PNAME%
	String sEnd;

	/**返回语句*/
	String sReturn;
	/**变量声明开始语句*/
	String sDeclareBegin;

	/**参数列表*/
	KvMap<String, Type> kvAfferentParams;

	/**声明变量列表*/
	KvMap<String, Type> kvDeclareParams;
	/**变量声明关键字*/
	String sDeclareKeyword;

	/**正文SQL列表*/
	ArrayList<Statement> arSqls;
	int index;
	
	/**SQL文件开始语句*/
	String sFileBegin;
	String sFileEnd;

	/**
	 * 构造方法 传入存储过程名称初始化
	 * @param name		存储过程物理名称
	 * @param begin		存储过程create语句
	 * @param end		存储过程end语句
	 */
	public Procedure(String name,String begin,String end){
		this.sName=name;
		this.kvAfferentParams=new KvMap<String, Type>();
		this.kvDeclareParams=new KvMap<String, Type>();
		this.arSqls=new ArrayList<Statement>();
		this.index=0;
		this.sBegin=begin;
		this.sEnd=end;
	}

	/**
	 * 放入一个外部传入的参数
	 * @param name		参数名称
	 * @param type		数据类型
	 * @throws ErrorMessage
	 */
	public void putAfferentParam(String name,Type type) throws ErrorMessage{
		this.kvAfferentParams.put(name, type);
	}

	/**
	 * 设置生命变量的关键字
	 * @param declareKeyword	变量声明关键字
	 * @param assignSymbol		复制符号
	 */
	public void setDeclareKeyword(String declareKeyword){
		this.sDeclareKeyword=declareKeyword;
	}
	
	/**
	 * 放入一个声明参数
	 * @param name		参数名称
	 * @param type		数据类型
	 * @throws ErrorMessage
	 */
	public void putDeclareParam(String name,Type type) throws ErrorMessage{
		this.kvDeclareParams.put(name,type);
	}

	/**
	 * 设置返回语句
	 * @param sReturn
	 */
	public void setReturn(String sReturn){
		this.sReturn=sReturn;
	}

	/**
	 * 设置变量声明的开始语句
	 * @param declareBegin
	 */
	public void setDeclareBegin(String declareBegin) {
		this.sDeclareBegin = declareBegin;
	}

	/**
	 * 放入一条正文语句
	 * @param sql	Statement
	 */
	public void putStatement(Statement sql){
		this.arSqls.add(this.index++, sql);
	}

	/**
	 * 返回存储过程的SQL
	 * @return
	 */
	public String getSql(){
		StringBuilder sb = new StringBuilder();

		//create语句
		sb.append(this.sBegin.replaceAll("%PNAME%", this.sName));

		//传入参数列表
		if(this.kvAfferentParams.size()>0)
			sb.append('(');
		for(Map.Entry<String,Type>ite:this.kvAfferentParams){
			sb.append(ite.getKey());
			sb.append(' ');
			sb.append(ite.getValue().toString());
			sb.append(',');
		}
		if(this.kvAfferentParams.size()>0){
			sb.delete(sb.length()-1,sb.length());
			sb.append(")\n");
		}

		//返回语句
		if(this.sReturn!=null){
			sb.append(this.sReturn);
			sb.append(";\n");
		}

		//声明参数列表
		if(this.kvDeclareParams.size()>0){
			if(this.sDeclareBegin!=null){
				sb.append(this.sDeclareBegin);
				sb.append('\n');
			}
			for(Map.Entry<String,Type>ite:this.kvDeclareParams){
				if(this.sDeclareKeyword!=null){
					sb.append(this.sDeclareKeyword);
					sb.append(' ');
				}
				sb.append(ite.getKey());
				sb.append(' ');
				sb.append(ite.getValue().toString());
				sb.append(";\n");
			}
		}
		
		//正文
		for(int i=0;i<this.index;i++){
			sb.append(this.arSqls.get(i).toString());
			sb.append(";\n");
		}

		//end语句
		sb.append(this.sEnd.replaceAll("%PNAME%", this.sName));
		sb.append('\n');
		
		return sb.toString();
	}
	
	/**
	 * 设置SQL文件结束语句
	 * @param fileBegin	生成SQL文件时的开始语句
	 */
	public void setFileBegin(String fileBegin) {
		this.sFileBegin = fileBegin;
	}

	/**
	 * 设置SQL文件结束语句
	 * @param fileEnd	生成SQL文件时的结束语句
	 */
	public void setFileEnd(String fileEnd) {
		this.sFileEnd = fileEnd;
	}

	/**
	 * 返回存储过程SQL文件的SQL
	 * @return	String
	 */
	public String getFileSql(){
		StringBuilder sb = new StringBuilder();
		if(this.sFileBegin!=null){
			sb.append(this.sFileBegin);
		}
		sb.append(this.getSql());
		if(this.sFileEnd!=null){
			sb.append(this.sFileEnd);
		}
		return sb.toString();
	}
}
